import React, { Fragment, useState } from 'react';
import 'antd/dist/antd.css';
import Sider from './components/Sider/Sider'
import Main from './components/Main/Main'
import './App.scss'
import { v4 as uuidv4 } from 'uuid';
import fileHelper from 'utils/fileHelper';
import config from 'components/common/Common';
import { objToArr, flattenArr, createDefaultTitle, judgeFileName } from 'utils/helper'
import useIpcRenderer from 'hooks/useIpcRenderer';
const { error, saveFilesToStore, getFiles, success, getSavedFileLocation, getAutoSync } = config
const { join, basename, dirname } = window.require('path')
const { remote, ipcRenderer } = window.require('electron')

function App() {
  const [files, setFiles] = useState(getFiles() || []) // 文件列表
  const [activeFileID, setActiveFileID] = useState(null) // 激活的文件ID
  const [openedFileIDs, setOpenedFileIDs] = useState([]); // 在标签中打开的文件ID列表
  const [unsaveFileIDs, setUnsaveFileIDs] = useState([]) // 未保存的文件ID列表
  const [searchFiles, setSearchFiles] = useState([]) // 搜索的文件列表
  const savedLocation = getSavedFileLocation() || remote.app.getPath('documents') // 打开的文件夹的位置
  const defaultBody = '## 在此输入Markdown文档'; // 新建文件时的默认内容
  const filesArr = objToArr(files)
  const fileListArr = (searchFiles.length > 0) ? searchFiles : filesArr; // 判断是否处于搜索状态

  // 获取已经打开的文件列表
  const openedFiles = openedFileIDs.map(openID => {
    return files[openID]
  })
  // 获取激活的文件信息
  const activeFile = activeFileID ? files[activeFileID] : null

  // 在侧边栏点击文件之后，将其添加到右侧的标签页中
  const fileClick = async (fileID) => {
    setActiveFileID(fileID) // 更改激活文件ID
    const currentFile = files[fileID]
    const { id, title, path, isLoaded } = currentFile
    if (!isLoaded) {
      try {
        if (getAutoSync()) { // 如果开启云端同步，则获取云端文件而不是获取本地文件
          ipcRenderer.send('download-file', {
            key: title,
            path,
            id
          })
        } else {
          const value = await fileHelper.readFile(currentFile.path)
          const newFile = { ...files[fileID], body: value, isLoaded: true } // 设置已加载状态
          setFiles({ ...files, [fileID]: newFile })
        }
      } catch (err) {
        error('该文件不存在')
        const { [fileID]: value, ...afterDelete } = files
        setFiles(afterDelete)
        saveFilesToStore(afterDelete)
        tabCLose(fileID)
        return;
      }
    }
    if (!openedFileIDs.includes(fileID)) {
      setOpenedFileIDs([...openedFileIDs, fileID])
    }
  }

  // 点击tab中的删除按钮，将此文件关闭
  const tabCLose = (id) => {
    const tabsWithout = openedFileIDs.filter(fileID => fileID !== id)
    setOpenedFileIDs(tabsWithout)
    // 删除后将activeID赋给第一个打开的文件
    if (tabsWithout.length > 0) {
      setActiveFileID(tabsWithout[0])
    } else {
      setActiveFileID(null)
    }
  }

  // 当文件内容改变之后，更新files里面的body，并且添加未保存
  const fileChange = (id, value) => {
    if (files[id].body === value) {
      return
    }
    const newFile = { ...files[id], body: value }
    setFiles({ ...files, [id]: newFile })
    if (!unsaveFileIDs.includes(id)) {
      setUnsaveFileIDs([...unsaveFileIDs, id])
    }
  }

  // 移除文件
  const removeFile = (id) => {
    const { [id]: value, ...afterDelete } = files
    tabCLose(id)
    setFiles(afterDelete)
    saveFilesToStore(afterDelete)
  }

  // 删除侧边栏中的文件
  const deleteFile = async (id) => {
    try {
      await fileHelper.deleteFile(files[id].path)
      removeFile(id)
      success('删除成功')
    } catch (err) {
      error(err.message)
    }
  }

  // 从侧边栏更新文件的名称
  const updateFIleName = (id, title, isNew) => {
    const reg = /.md/;
    const file = files[id]
    const newTitle = reg.test(title) ? title : title + '.md'; // 验证是否有.md后缀结尾
    if (judgeFileName(filesArr, newTitle) && !isNew) {
      error('文件名重复，请修改命名')
      return
    }
    const newPath = isNew ? join(savedLocation, newTitle) : join(dirname(file.path), newTitle) // 新的路径
    const oldPath = file.path // 旧的路径
    const modifiedFile = { ...file, title: newTitle, path: newPath, isNew: false } // 改变之后的文件信息
    const newFiles = { ...files, [id]: modifiedFile }
    fileHelper.renameFile(oldPath, newPath) // 重命名文件
    setFiles(newFiles) // 将state中的files更新
    saveFilesToStore(newFiles) // 将store中的files更新
  }

  // 侧边栏搜索
  const fileSearch = (keyword) => {
    const newFiles = filesArr.filter(file => file.title.includes(keyword))
    setSearchFiles(newFiles)
  }

  // 新建文件
  const createNewFile = () => {
    const newID = uuidv4()
    const defaultTitle = createDefaultTitle(filesArr) // 生成默认的标题
    const defaultPath = join(savedLocation, defaultTitle) // 默认的地址
    fileHelper.writeFile(defaultPath, defaultBody)
    const newFile = {
      id: newID,
      title: defaultTitle,
      path: defaultPath,
      body: defaultBody,
      createdAt: new Date().getTime(),
      isNew: true
    }
    setFiles({ ...files, [newID]: newFile })
  }

  // 保存文件
  const saveCurrentFile = async () => {
    const { path, body, title } = activeFile
    fileHelper.writeFile(path, body).then((err) => {
      if (err) {
        error(err.message)
      }
      setUnsaveFileIDs(unsaveFileIDs.filter(id => id !== activeFile.id))
      // 如果用户填写完成七牛云配置信息，并且选择自动同步，则发送信号以便保存文件到云端
      if (getAutoSync()) {
        ipcRenderer.send('upload-file', {
          key: title,
          path,
        })
      }
    })
  }

  // 导入文件
  const importFiles = () => {
    remote.dialog.showOpenDialog({
      title: '选择导入的 Markdown 文件',
      properties: ['openFile', 'multiSelections'],
      filters: [
        {
          name: 'Markdown files',
          extensions: ['md']
        }
      ]
    }, (paths) => {
      if (Array.isArray(paths)) {
        // 筛选出未添加的路径
        const filterPaths = paths.filter(path => {
          // 将files对象中的value变为数组，从而寻找相同的path
          const alreadyAdded = Object.values(files).find(file => {
            return file.path === path
          })
          return !alreadyAdded
        })

        // 获取由指定属性构成的importFiles
        const importFilesArr = filterPaths.map(path => {
          return {
            id: uuidv4(),
            title: basename(path),
            path,
          }
        })

        const newFiles = { ...files, ...flattenArr(importFilesArr) };
        setFiles(newFiles);
        saveFilesToStore(newFiles)
        if (importFilesArr.length > 0) {
          success(`成功导入${importFilesArr.length}个文件`)
        }
      }
    })
  }

  // 同步到云端后，给对应文件增加已同步的标志并且添加时间
  const activeFileUploaded = () => {
    success('已成功同步到云端')
    const { id } = activeFile
    const modifiedFile = { ...files[id], isSynced: true, updatedAt: new Date().getTime() }
    const newFiles = { ...files, [id]: modifiedFile }
    setFiles(newFiles)
    saveFilesToStore(newFiles)
  }

  const activeFileDownloaded = (event, message) => {
    const currentFile = files[message.id]
    const { id, path } = currentFile
    fileHelper.readFile(path).then(value => {
      let newFile;
      if (message.status === 'download-success') {
        newFile = { ...files[id], body: value, isLoaded: true, isSynced: true, updatedAt: new Date().getTime() }
      } else {
        newFile = { ...files[id], body: value, isLoaded: true }
      }
      const newFiles = { ...files, [id]: newFile }
      setFiles(newFiles);
      saveFilesToStore(newFiles)
    })
  }

  useIpcRenderer({
    'create-new-file': createNewFile,
    'import-file': importFiles,
    'active-file-uploaded': activeFileUploaded,
    'file-downloaded': activeFileDownloaded,
  })

  return (
    <Fragment>
      <div className='app'>
        <Sider
          onFileClick={fileClick}
          files={fileListArr}
          fileSearch={fileSearch}
          createNewFile={createNewFile}
          updateFIleName={updateFIleName}
          importFiles={importFiles}
          deleteFile={deleteFile}
          removeFile={removeFile}
        />
        <Main
          openFiles={openedFiles}
          activeID={activeFileID}
          unsaveIDs={unsaveFileIDs}
          activeFile={activeFile}
          setActiveFileID={setActiveFileID}
          tabCLose={tabCLose}
          fileChange={fileChange}
          saveCurrentFile={saveCurrentFile}
        />
      </div>
      <script src="./font/iconfont.js"></script>
    </Fragment>
  );
}

export default App;
